package MutilReadFile;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class LineCounter2 {

	public static void main(String[] args) throws Exception {
		File file = new File("C:\\a.txt");
		int bufferSize =2048;//32768;
		long begin = System.nanoTime();
		int threads =Runtime.getRuntime().availableProcessors();//获取cpu线程数
		long line = calculate(file, threads, bufferSize);
		long end = System.nanoTime();
 		//System.out.println(line + "行");
//		System.out.println((end - begin) / 1000 + "微秒");
	}

	private static class FilePartCallable implements Callable<Long> {
		private int bufferSize;
		private File file;
		private long start;
		private long count;

		public FilePartCallable(File file, long start, long count,
				int bufferSize) {
			this.file = file;
			this.start = start;
			this.count = count;
			this.bufferSize = bufferSize;
		}

		private long read(File file, long start, long count) throws IOException {
			if (count == 0) {
				return 0;
			}
			RandomAccessFile raf = new RandomAccessFile(file, "r");
			raf.seek(start);

			int len = count < bufferSize ? (int) count : bufferSize;
			long lines = 0L, c = count / len;
			byte[] buffer = new byte[len];

			for (int i = 0; i < c; i++) {
			 raf.read(buffer);
			 System.out.write(buffer, 0, len);
			}
			int rest = (int) (count % len);
			raf.read(buffer, 0, rest);
			 System.out.write(buffer, 0, rest);
			// System.err.print("###############################################");
			raf.close();
			return lines;
		}

		public Long call() throws Exception {
			return Long.valueOf(read(file, start, count));
		}
	}

	private static long calculate(File file, int threads, int bufferSize)
			throws Exception {
		ExecutorService es = Executors.newFixedThreadPool(threads);
		CompletionService<Long> cs = new ExecutorCompletionService<Long>(es);
		long size = file.length();
		long count = size / threads;
		for (int i = 0; i < threads; i++) {
			long start = count * i;
			cs.submit(new FilePartCallable(file, start, count, bufferSize));
		}

		long start = count * threads;
		long restCount = size - start;
		cs.submit(new FilePartCallable(file, start, restCount, bufferSize));

		long lines = 0L;
		for (int i = 0; i < threads + 1; i++) {
			lines += cs.take().get();
		}

		es.shutdown();
		return lines + 1;
	}
}
